package org.acm.seguin.refactor.type; import java.io.File; import java.util.LinkedList; import java.util.StringTokenizer; import org.acm.seguin.parser.ast.ASTName; import org.acm.seguin.refactor.AddImportTransform; import org.acm.seguin.refactor.ComplexTransform; import org.acm.seguin.refactor.RemoveImportTransform; import org.acm.seguin.refactor.TransformAST; import org.acm.seguin.summary.FileSummary; import org.acm.seguin.summary.ImportSummary; import org.acm.seguin.summary.PackageSummary; import org.acm.seguin.summary.Summary; import org.acm.seguin.summary.TypeSummary; import org.acm.seguin.summary.query.GetTypeSummary; /** * Renames a class from one name to another. * *@author Chris Seguin */ public class RenameClassVisitor extends TypeChangeVisitor { // Instance Variables /** * Description of the Field */ protected String packageName; /** * Description of the Field */ protected String oldClassName; /** * Description of the Field */ protected String newClassName; private File base; private File targetFile; /** * Determine if anything in this tree references these classes. * *@param base the base directory *@param packageName Description of Parameter *@param oldClass Description of Parameter *@param newClass Description of Parameter *@param complex Description of Parameter */ public RenameClassVisitor(String packageName, String oldClass, String newClass, File base, ComplexTransform complex) { super(complex); this.packageName = packageName; this.base = base; oldClassName = oldClass; newClassName = newClass; } /** * Gets the File Specific Transform * *@param summary Gets a file specific transform *@return The FileSpecificTransform value */ protected TransformAST getFileSpecificTransform(FileSummary summary) { if (isRenamingTarget(summary)) { ASTName oldName = new ASTName(0); oldName.fromString(oldClassName); ASTName newName = new ASTName(0); newName.fromString(newClassName); return new RenameTypeTransform(oldName, newName, GetTypeSummary.query(packageName, oldClassName)); } return null; } /** * Gets the New Imports transform * *@param node the file summary *@param className the name of the class that is changing *@return The NewImports value */ protected AddImportTransform getNewImports(FileSummary node, String className) { if (GetTypeSummary.query(node, newClassName) == null) { return new AddImportTransform(packageName, newClassName); } else { return null; } } /** * Gets the Remove Imports transform * *@param node the import summary *@return The transform */ protected RemoveImportTransform getRemoveImportTransform(ImportSummary node) { return new RemoveImportTransform(packageName, oldClassName); } /** * Gets the AppropriateClasses attribute of the TypeChangeVisitor object * *@param node Description of Parameter *@return The AppropriateClasses value */ protected LinkedList getAppropriateClasses(FileSummary node) { LinkedList result = new LinkedList(); result.add(oldClassName); return result; } /** * Gets the reference to the file where the refactored output should be sent * *@param node the files summary *@return The NewFile value */ protected File getNewFile(FileSummary node) { File current = base; StringTokenizer tok = new StringTokenizer(packageName, "."); while (tok.hasMoreTokens()) { current = new File(current, tok.nextToken()); } File input = new File(current, oldClassName + ".java"); if (checkFiles(input, node.getFile())) { File result = new File(current, newClassName + ".java"); return result; } else { return node.getFile(); } } /** * Return the current package * *@return the current package of the class */ protected String getCurrentPackage() { return packageName; } /** * Gets the new name * *@return an ASTName containing the new name */ protected ASTName getNewName() { ASTName result = new ASTName(0); result.fromString(packageName); result.addNamePart(newClassName); return result; } /** * Gets the RenamingTransform * *@param refactoring the refactoring *@param node the file summary to reference *@param className the name of the class that is changing */ protected void addRenamingTransforms(ComplexTransform refactoring, FileSummary node, String className) { ASTName oldOne = new ASTName(0); oldOne.addNamePart(oldClassName); TypeSummary importedType = GetTypeSummary.query(node, newClassName); if ((importedType != null) && isRenamingTarget(node)) { renameRefactoringTarget(refactoring, node, className, oldOne, importedType); } else if (importedType != null) { alreadyImportsType(refactoring, oldOne, node, importedType); } else { simpleRename(refactoring, oldOne); } refactoring.add(new RenameTypeTransform(getOldName(), getNewName(), GetTypeSummary.query(packageName, oldClassName))); } /** * We are performing the transformation on a refactoring that already has * that type imported from another class * *@param refactoring the complex transformation *@param oldOne the old class name *@param node the file that is being changed *@param importedType the type that we are supposedly importing */ protected void alreadyImportsType(ComplexTransform refactoring, ASTName oldOne, FileSummary node, TypeSummary importedType) { refactoring.add(new RenameTypeTransform(oldOne, getNewName(), GetTypeSummary.query(packageName, oldClassName))); } /** * Checks to see if this is the target * *@param summary the file summary *@return true if this file summary represents the file that is * being renamed */ private boolean isRenamingTarget(FileSummary summary) { if (targetFile == null) { File current = base; StringTokenizer tok = new StringTokenizer(packageName, "."); while (tok.hasMoreTokens()) { current = new File(current, tok.nextToken()); } targetFile = new File(current, oldClassName + ".java"); } return checkFiles(targetFile, summary.getFile()); } /** * Creates a name from a type summary * *@param summary the type summary *@return the name */ private ASTName getImport(TypeSummary summary) { ASTName name = new ASTName(0); Summary current = summary.getParent(); while (!(current instanceof PackageSummary)) { current = current.getParent(); } name.fromString(((PackageSummary) current).getName()); name.addNamePart(summary.getName()); return name; } /** * Gets the old name * *@return an ASTName containing the old name */ private ASTName getOldName() { ASTName result = new ASTName(0); result.fromString(packageName); result.addNamePart(oldClassName); return result; } /** * This file does not import the type, so the rename operation is simple * *@param refactoring the complex transformation *@param oldOne the old one */ private void simpleRename(ComplexTransform refactoring, ASTName oldOne) { ASTName newOne = new ASTName(0); newOne.addNamePart(newClassName); refactoring.add(new RenameTypeTransform(oldOne, newOne, GetTypeSummary.query(packageName, oldClassName))); } /** * We are attempting to perform the rename operation on the targeted file. * This change is complex because the file already imported another class * with the same name * *@param refactoring the complex transformation *@param node the node *@param className the new name *@param oldOne the old class *@param importedType the type that was imported that has the same name */ private void renameRefactoringTarget(ComplexTransform refactoring, FileSummary node, String className, ASTName oldOne, TypeSummary importedType) { ASTName newOne = new ASTName(0); newOne.addNamePart(newClassName); ASTName importedTypeName = getImport(importedType); refactoring.add(new RenameTypeTransform(newOne, importedTypeName, GetTypeSummary.query(packageName, oldClassName))); refactoring.add(new RemoveImportTransform(importedTypeName)); refactoring.add(new RenameTypeTransform(oldOne, newOne, GetTypeSummary.query(packageName, oldClassName))); } /** * Description of the Method * *@param file1 Description of Parameter *@param file2 Description of Parameter *@return Description of the Returned Value */ private boolean checkFiles(File file1, File file2) { try { String one = file1.getCanonicalPath(); String two = file2.getCanonicalPath(); return one.equals(two); } catch (java.io.IOException ioe) { return false; } } }